 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.core.internal.registry;

 import java.util.Hashtable ;
 import org.eclipse.core.runtime.*;
 import org.eclipse.core.runtime.spi.RegistryContributor;
 import org.eclipse.osgi.util.NLS;

 /**
  * An object which represents the user-defined contents of an extension
  * in a plug-in manifest.
  */
 public class ConfigurationElement extends RegistryObject {
     static final ConfigurationElement[] EMPTY_ARRAY = new ConfigurationElement[0];

     //The id of the parent element. It can be a configuration element or an extension
 int parentId;
     byte parentType; //This value is only interesting when running from cache.

     //Store the properties and the value of the configuration element.
 //The format is the following:
 // [p1, v1, p2, v2, configurationElementValue]
 //If the array size is even, there is no "configurationElementValue (ie getValue returns null)".
 //The properties and their values are alternated (v1 is the value of p1).
 private String [] propertiesAndValue;

     //The name of the configuration element
 private String name;

     //ID of the actual contributor of this element
 //This value can be null when the element is loaded from disk and the owner has been uninstalled.
 //This happens when the configuration is obtained from a delta containing removed extension.
 private String contributorId;

     protected ConfigurationElement(ExtensionRegistry registry, boolean persist) {
         super(registry, persist);
     }

     protected ConfigurationElement(int self, String contributorId, String name, String [] propertiesAndValue, int[] children, int extraDataOffset, int parent, byte parentType, ExtensionRegistry registry, boolean persist) {
         super(registry, persist);

         setObjectId(self);
         this.contributorId = contributorId;
         this.name = name;
         this.propertiesAndValue = propertiesAndValue;
         setRawChildren(children);
         setExtraDataOffset(extraDataOffset);
         parentId = parent;
         this.parentType = parentType;
     }

     void throwException(String message, Throwable exception) throws CoreException {
         throw new CoreException(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, IRegistryConstants.PLUGIN_ERROR, message, exception));
     }

     protected String getValue() {
         return getValueAsIs();
     }

     String getValueAsIs() {
         if (propertiesAndValue.length != 0 && propertiesAndValue.length % 2 == 1)
             return propertiesAndValue[propertiesAndValue.length - 1];
         return null;
     }

     public String getAttribute(String attrName) {
         return getAttributeAsIs(attrName);
     }

     String getAttributeAsIs(String attrName) {
         if (propertiesAndValue.length <= 1)
             return null;
         int size = propertiesAndValue.length - (propertiesAndValue.length % 2);
         for (int i = 0; i < size; i += 2) {
             if (propertiesAndValue[i].equals(attrName))
                 return propertiesAndValue[i + 1];
         }
         return null;
     }

     protected String [] getAttributeNames() {
         if (propertiesAndValue.length <= 1)
             return RegistryObjectManager.EMPTY_STRING_ARRAY;

         int size = propertiesAndValue.length / 2;
         String [] result = new String [size];
         for (int i = 0; i < size; i++) {
             result[i] = propertiesAndValue[i * 2];
         }
         return result;
     }

     void setProperties(String [] value) {
         propertiesAndValue = value;
     }

     protected String [] getPropertiesAndValue() {
         return propertiesAndValue;
     }

     void setValue(String value) {
         if (propertiesAndValue.length == 0) {
             propertiesAndValue = new String [] {value};
             return;
         }
         if (propertiesAndValue.length % 2 == 1) {
             propertiesAndValue[propertiesAndValue.length - 1] = value;
             return;
         }
         String [] newPropertiesAndValue = new String [propertiesAndValue.length + 1];
         System.arraycopy(propertiesAndValue, 0, newPropertiesAndValue, 0, propertiesAndValue.length);
         newPropertiesAndValue[propertiesAndValue.length] = value;
         propertiesAndValue = newPropertiesAndValue;
     }

     void setContributorId(String id) {
         this.contributorId = id;
     }

     protected String getContributorId() {
         return contributorId;
     }

     public ConfigurationElement[] getChildren(String childrenName) {
         if (getRawChildren().length == 0)
             return ConfigurationElement.EMPTY_ARRAY;

         ConfigurationElement[] result = new ConfigurationElement[1]; //Most of the time there is only one match
 int idx = 0;
         RegistryObjectManager objectManager = registry.getObjectManager();
         for (int i = 0; i < children.length; i++) {
             ConfigurationElement toTest = (ConfigurationElement) objectManager.getObject(children[i], noExtraData() ? RegistryObjectManager.CONFIGURATION_ELEMENT : RegistryObjectManager.THIRDLEVEL_CONFIGURATION_ELEMENT);
             if (toTest.name.equals(childrenName)) {
                 if (idx != 0) {
                     ConfigurationElement[] copy = new ConfigurationElement[result.length + 1];
                     System.arraycopy(result, 0, copy, 0, result.length);
                     result = copy;
                 }
                 result[idx++] = toTest;
             }
         }
         if (idx == 0)
             result = ConfigurationElement.EMPTY_ARRAY;
         return result;
     }

     void setParentId(int objectId) {
         parentId = objectId;
     }

     protected String getName() {
         return name;
     }

     void setName(String name) {
         this.name = name;
     }

     void setParentType(byte type) {
         parentType = type;
     }

     public IContributor getContributor() {
         return registry.getObjectManager().getContributor(contributorId);
     }

     protected Object createExecutableExtension(String attributeName) throws CoreException {
         String prop = null;
         String executable;
         String contributorName = null;
         String className = null;
         Object initData = null;
         int i;

         if (attributeName != null)
             prop = getAttribute(attributeName);
         else {
             // property not specified, try as element value
 prop = getValue();
             if (prop != null) {
                 prop = prop.trim();
                 if (prop.equals("")) //$NON-NLS-1$
 prop = null;
             }
         }

         if (prop == null) {
             // property not defined, try as a child element
 ConfigurationElement[] exec;
             ConfigurationElement[] parms;
             ConfigurationElement element;
             Hashtable initParms;
             String pname;

             exec = getChildren(attributeName);
             if (exec.length != 0) {
                 element = exec[0]; // assumes single definition
 contributorName = element.getAttribute("plugin"); //$NON-NLS-1$
 className = element.getAttribute("class"); //$NON-NLS-1$
 parms = element.getChildren("parameter"); //$NON-NLS-1$
 if (parms.length != 0) {
                     initParms = new Hashtable (parms.length + 1);
                     for (i = 0; i < parms.length; i++) {
                         pname = parms[i].getAttribute("name"); //$NON-NLS-1$
 if (pname != null)
                             initParms.put(pname, parms[i].getAttribute("value")); //$NON-NLS-1$
 }
                     if (!initParms.isEmpty())
                         initData = initParms;
                 }
             } else {
                 // specified name is not a simple attribute nor child element
 throwException(NLS.bind(RegistryMessages.exExt_extDefNotFound, attributeName), null);
             }
         } else {
             // simple property or element value, parse it into its components
 i = prop.indexOf(':');
             if (i != -1) {
                 executable = prop.substring(0, i).trim();
                 initData = prop.substring(i + 1).trim();
             } else
                 executable = prop;

             i = executable.indexOf('/');
             if (i != -1) {
                 contributorName = executable.substring(0, i).trim();
                 className = executable.substring(i + 1).trim();
             } else
                 className = executable;
         }

         // create a new instance
 RegistryContributor defaultContributor = registry.getObjectManager().getContributor(contributorId);
         Object result = registry.createExecutableExtension(defaultContributor, className, contributorName);

         // Check if we have extension adapter and initialize;
 // Make the call even if the initialization string is null
 try {
             // We need to take into account both "old" and "new" style executable extensions
 ConfigurationElementHandle confElementHandle = new ConfigurationElementHandle(registry.getObjectManager(), getObjectId());
             if (result instanceof IExecutableExtension)
                 ((IExecutableExtension) result).setInitializationData(confElementHandle, attributeName, initData);
         } catch (CoreException ce) {
             // user code threw exception
 throw ce;
         } catch (Exception te) {
             // user code caused exception
 throwException(NLS.bind(RegistryMessages.plugin_initObjectError, getContributor().getName(), className), te);
         }

         // Deal with executable extension factories.
 if (result instanceof IExecutableExtensionFactory)
             result = ((IExecutableExtensionFactory) result).create();

         return result;
     }

 }

